import hashlib
import json
import datetime
import os

import pandas as pd
from io import BytesIO

import minio
from django.http import HttpResponse, HttpResponseRedirect
from django.shortcuts import render, redirect
from django.views.decorators.clickjacking import xframe_options_sameorigin

from report.models import FileRptJgTz, RptJgTz, RptImprove, RptInspection, FileRptImprove, FileRptInspection
from share_report.forms import UploadFileForm

MINIO_SERVER = '10.101.0.204:9000'
# MINIO_SERVER = '127.0.0.1:9000'
PROJECT = ['社内加工班履历', '涂装班履历', '社外不良改善活动履历', '社外工程检查履历']
DBS = [RptJgTz, RptJgTz, RptImprove, RptInspection]
FILES = [FileRptJgTz, FileRptJgTz, FileRptImprove, FileRptInspection]
BUCKETS = ['rpt-jgtz', 'rpt-jgtz', 'rpt-improve', 'rpt-inspection']


def index_view(request, idx):
    title = PROJECT[idx]

    return render(request, 'report/index.html', {'title': title, 'idx': idx})


def about_view(request):
    return render(request, 'report/about.html')


# 生成响应
def make_response(status=200, content_type='text/plain', content=None):
    """ Construct a response to an upload request.
    Success is indicated by a status of 200 and { "success": true }
    contained in the content.

    Also, content-type is text/plain by default since IE9 and below chokes
    on application/json. For CORS environments and IE9 and below, the
    content-type needs to be text/html.
    """
    response = HttpResponse()
    response.status_code = status
    response['Content-Type'] = content_type
    response.content = content
    return response


# 保存函数定义


# excel 提交
def post(request, idx):
    """
    A POST request. Validate the form and then handle the upload
    based ont the POSTed data. Does not handle extra parameters yet.
    """

    created = 0
    updated = 0
    total = 0

    form = UploadFileForm(request.POST, request.FILES)
    if form.is_valid():
        file = request.FILES['qqfile']
        # 读文件到内存
        f = BytesIO()
        for c in file.chunks():
            f.write(c)
        df = pd.read_excel(f, engine='openpyxl')
        # 填空 NaN
        df.drop(['序号'], axis=1, inplace=True)
        df.dropna(how='all', inplace=True)
        df.fillna('', inplace=True)
        df_dict = df.to_dict(orient='records')
        total = len(df_dict)
        # 保存到数据库
        err = ''
        procedure = '加工'  # 区分0, 1
        if idx == 1:
            procedure = '涂装'
        for d in df_dict:
            is_created = False
            # 选择数据库、字段
            if idx == 0 or idx == 1:
                # 加工/涂装，11字段
                defaults = {
                    'factory': d['工厂'],
                    'product': d['品名'],
                    'procedure': procedure,
                    'mold_no': d['模具号'],
                    'time_of_incident': d['发生时间'],
                    'problem': d['问题点'],
                    'improvement': d['改善内容'],
                    'stage': d['改善时间段'],
                    'before': d['改善前'],
                    'after': d['改善后'],
                    'is_ok': d['改善结果判定'] == 'OK',
                    'note': d['备注']
                }
                try:
                    obj, is_created = RptJgTz.objects.update_or_create(
                        factory=d['工厂'], product=d['品名'], mold_no=d['模具号'],
                        defaults=defaults
                    )
                except Exception as e:
                    err = str(e)
                    break

            if idx == 2:
                # 社外不良改善
                defaults = {
                    'customer_agency': d['顾客社'],
                    'contact': d['联系人'],
                    'time_of_incident': d['发生时间'],
                    'time_of_receive': d['接收时间'],
                    'product': d['品名'],
                    'num': d['发生数量'],
                    'problem': d['问题点'],
                    'info_lot': d['LOT信息'],
                    'loc_of_incident': d['发生问题工序'],
                    'improvement_temporary': d['临时对策'],
                    'improvement_essential': d['根本对策'],
                    'is_ok': d['改善对策\n是否反馈完成'] == '是',
                    'note': d['备注']
                }
                try:
                    obj, is_created = RptImprove.objects.update_or_create(
                        customer_agency=d['顾客社'],
                        time_of_incident=d['发生时间'],
                        product=d['品名'],
                        defaults=defaults
                    )
                except Exception as e:
                    err = str(e)
                    break

            if idx == 3:
                # 社外工程
                defaults = {
                    'customer_agency': d['顾客社'],
                    'inspector': d['检查员'],
                    'time_of_inspection': d['检查时间'],
                    'item': d['检查项目'],
                    'is_feedback': d['改善对策\n是否反馈完成'] == '是',
                    'is_ok': d['检查结果'] == 'PASS',
                    'note': d['备注']
                }
                try:
                    obj, is_created = RptInspection.objects.update_or_create(
                        customer_agency=d['顾客社'],
                        time_of_inspection=d['检查时间'],
                        item=d['检查项目'],
                        defaults=defaults
                    )
                except Exception as e:
                    err = str(e)
                    break

            if is_created:
                created += 1
            else:
                updated += 1

        # 输出html
        print(err)
        html = ''
        return make_response(content=json.dumps({'success': True, 'p': html, 'err': err,
                                                 'result': '总数：%d，创建：%d，更新：%d' % (total, created, updated)}))
    else:
        return make_response(status=400,
                             content=json.dumps({
                                 'success': False,
                                 'error': '%s' % repr(form.errors)
                             }))


def rpt_post(request, idx, pk):
    errs = ''
    need_save = False  # 需要保存

    form = UploadFileForm(request.POST, request.FILES)
    if form.is_valid():
        file = request.FILES['qqfile']
        name, ext = os.path.splitext(file.name)
        # 读文件到内存
        f = BytesIO()
        for c in file.chunks():
            f.write(c)

        # 计算hash
        md5 = hashlib.md5(f.getbuffer()).hexdigest()

        f.seek(0)
        raw_size = f.getbuffer().nbytes

        # 报告/文件 数据表变量
        db = DBS[idx]
        file_db = FILES[idx]

        version = 0
        try:
            q = None
            if idx == 0 or idx == 1:
                q = file_db.objects.filter(jgtz_log=pk).order_by('-version')  # 此改进下，且md5相同
            if idx == 2:
                q = file_db.objects.filter(improve_log=pk).order_by('-version')
            if idx == 3:
                q = file_db.objects.filter(inspection_log=pk).order_by('-version')

            # 当前版本号
            if q.count() > 0:
                version = q[0].version
            q = q.filter(md5=md5)
            # md5检验，是否已存在
            if q.count() == 0:
                version += 1
                need_save = True
        except (db.DoesNotExist, IndexError):
            pass
        if need_save:
            # 目录
            bucket = BUCKETS[idx]
            # 文件名
            file_name = '%s-%s-v%d.%s' % (name, pk, version, ext)
            # 写文件到s3
            client = minio.Minio(MINIO_SERVER, access_key='minioadmin', secret_key='minioadmin', secure=False)
            if not client.bucket_exists(bucket):
                client.make_bucket(bucket)

            etag = client.put_object(bucket, file_name, data=f, length=raw_size)

            print('md5:%s, etag:%s' % (md5, etag.etag))
            if md5 != etag.etag:
                errs = 'hash 错误'

            # 存到数据库
            if idx == 0 or idx == 1:
                obj = file_db.objects.create(
                    title=name,
                    filename_saved=file_name,
                    md5=md5,
                    version=version,
                    note=request.POST['note'],
                    jgtz_log=db.objects.get(pk=pk)
                )
            if idx == 2:
                obj = file_db.objects.create(
                    title=name,
                    filename_saved=file_name,
                    md5=md5,
                    version=version,
                    note=request.POST['note'],
                    improve_log=db.objects.get(pk=pk)
                )
            if idx == 3:
                obj = file_db.objects.create(
                    title=name,
                    filename_saved=file_name,
                    md5=md5,
                    version=version,
                    note=request.POST['note'],
                    inspection_log=db.objects.get(pk=pk)
                )
        # form is valid, return
        return make_response(content=json.dumps({'success': True, 'err': [], }))
    else:
        return make_response(status=400,
                             content=json.dumps({
                                 'success': False,
                                 'error': '%s' % repr(form.errors)
                             }))


# 取文件链接
def get_file_link(request, idx, pk):
    file_db = FILES[idx]
    bucket = BUCKETS[idx]
    rec = file_db.objects.get(pk=pk)
    client = minio.Minio(MINIO_SERVER, access_key='minioadmin', secret_key='minioadmin', secure=False)
    url = client.presigned_get_object(bucket,
                                      rec.filename_saved,
                                      expires=datetime.timedelta(days=1),
                                      response_headers={'Content-Disposition': 'filename="%s"' % rec.title}
                                      )
    return redirect(url)


# 查询
def query_view(request, idx):
    db = DBS[idx]
    file_db = FILES[idx]
    # 表格数据
    if idx == 0:
        qs = db.objects.filter(procedure='加工').values()
    elif idx == 1:
        qs = db.objects.filter(procedure='涂装').values()
    else:
        qs = db.objects.all().values()

    data = [q for q in qs]
    for d in data:
        # 添加子节点显示文件
        qs = None
        if idx == 0:
            qs = file_db.objects.filter(jgtz_log__id=d['id'], jgtz_log__procedure='加工')
        if idx == 1:
            qs = file_db.objects.filter(jgtz_log__id=d['id'], jgtz_log__procedure='涂装')
        if idx == 2:
            qs = file_db.objects.filter(improve_log__id=d['id'])
        if idx == 3:
            qs = file_db.objects.filter(inspection_log__id=d['id'])
        d['docs'] = qs.count()
        for k, v in d.items():
            if isinstance(v, datetime.date):
                d[k] = datetime.date.strftime(v, '%Y/%m/%d')
            if isinstance(v, bool):
                d[k] = 'OK'
                if k == '改善对策\n是否反馈完成':
                    d[k] = '是'
                if k == '检查结果':
                    d[k] = 'PASS'

    cols = []
    if idx == 0 or idx == 1:
        cols = [
            {'title': '工厂', 'field': 'factory', 'width': 90},
            {'title': '品名', 'field': 'product'},
            {'title': '模具号', 'field': 'mold_no'},
            {'title': '发生时间', 'field': 'time_of_incident'},
            {'title': '问题点', 'field': 'problem', 'formatter': "textarea", 'width': 200},
            {'title': '改善内容', 'field': 'improvement', 'formatter': "textarea", 'width': 300},
            {'title': '改善时间段', 'field': 'stage', 'formatter': "textarea"},
            {'title': '改善前', 'field': 'before', 'formatter': "textarea"},
            {'title': '改善后', 'field': 'after', 'formatter': "textarea"},
            {'title': '改善结果判定', 'field': 'is_ok'},
            {'title': '备注', 'field': 'note'},
        ]
    if idx == 2:
        cols = [
            {'title': '顾客社', 'field': 'customer_agency', 'width': 90},
            {'title': '联系人', 'field': 'contact'},
            {'title': '发生时间', 'field': 'time_of_incident'},
            {'title': '接收时间', 'field': 'time_of_receive'},
            {'title': '品名', 'field': 'product'},
            {'title': '发生数量', 'field': 'num'},
            {'title': '问题点', 'field': 'problem', 'formatter': "textarea", 'width': 300},
            {'title': 'LOT信息', 'field': 'info_lot', 'formatter': "textarea"},
            {'title': '发生问题工序', 'field': 'loc_of_incident', 'formatter': "textarea"},
            {'title': '临时对策', 'field': 'improvement_temporary', 'formatter': "textarea"},
            {'title': '根本对策', 'field': 'improvement_essential', 'formatter': "textarea", 'width': 300},
            {'title': '改善对策\n是否反馈完成', 'field': 'is_ok'},
            {'title': '备注', 'field': 'note'},
        ]
    if idx == 3:
        cols = [
            {'title': '顾客社', 'field': 'customer_agency', 'width': 90},
            {'title': '检查员', 'field': 'inspector'},
            {'title': '检查时间', 'field': 'time_of_inspection', 'widht': 300},
            {'title': '检查项目', 'field': 'item'},
            {'title': '改善对策\n是否反馈完成', 'field': 'is_feedback'},
            {'title': '检查结果', 'field': 'is_ok'},
            {'title': '备注', 'field': 'note'},
        ]

    return render(request, 'report/query.html', {'data': data, 'idx': idx, 'title': PROJECT[idx], 'cols': cols})


# 附加报告view
@xframe_options_sameorigin
def rpt_view(request, idx):
    db = FILES[idx]
    pk = request.GET['p']
    rpt_num = 0
    reports = []

    qs = None
    if idx == 0 or idx == 1:
        qs = db.objects.filter(jgtz_log__id=pk)
    if idx == 2:
        qs = db.objects.filter(improve_log__id=pk)
    if idx == 3:
        qs = db.objects.filter(inspection_log__id=pk)

    if qs.count() > 0:
        reports = [{'pk': q.id, '标题': q.title, '文件': q.filename_saved, '版本': q.version} for q in qs]
        rpt_num = qs.count()
    return render(request, 'report/rpt_upload.html', {'idx': idx, 'pk': pk, 'reports': reports, 'rpt_num': rpt_num})


def login(request):
    path = request.get_full_path()
    print(path)
    return HttpResponseRedirect('/accounts/signout/?next=' + path)


def error403(request):
    return render(request, '403.html')
